/*
 * Copyright (c) 2024 Endless
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "hal_network.h"
#include <array>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <memory>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <unistd.h>

namespace El {
namespace Hal {

namespace {
// 配置文件路径
const std::string DNS_CONFIG_FILE = "/etc/resolv.conf";
const std::string DHCP_COMMAND = "udhcpc";

// 命令超时时间(毫秒)
const int COMMAND_TIMEOUT_MS = 5000;

// 安全地执行命令并获取输出
std::string ExecCommandSafe(const char *cmd)
{
    std::array<char, 4096> buffer;
    std::string result;
    std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);

    if (!pipe) {
        return "";
    }

    while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
        result += buffer.data();
    }

    return result;
}

// 获取IPv4子网掩码的CIDR表示(即位数)
int GetNetmaskPrefix(const std::string &netmask)
{
    std::vector<int> parts;
    std::istringstream tokenStream(netmask);
    std::string token;

    while (getline(tokenStream, token, '.')) {
        parts.push_back(std::stoi(token));
    }

    if (parts.size() != 4) {
        return 0;
    }

    int prefixLength = 0;
    for (int part : parts) {
        for (int bit = 7; bit >= 0; --bit) {
            if ((part & (1 << bit)) != 0) {
                ++prefixLength;
            } else {
                // 子网掩码必须是连续的1，如果出现了0，后面应该都是0
                break;
            }
        }
    }

    return prefixLength;
}

// 将CIDR格式转换为子网掩码
std::string CidrToNetmask(int cidr)
{
    if (cidr < 0 || cidr > 32) {
        return "";
    }

    uint32_t mask = (cidr == 0) ? 0 : static_cast<uint32_t>(~0) << (32 - cidr);
    std::ostringstream oss;
    oss << ((mask >> 24) & 0xFF) << '.' << ((mask >> 16) & 0xFF) << '.' << ((mask >> 8) & 0xFF) << '.' << (mask & 0xFF);

    return oss.str();
}
} // namespace

NetworkManager::NetworkManager()
{
    // 构造函数实现
}

NetworkManager::~NetworkManager()
{
    // 析构函数实现
}

NetworkManager &NetworkManager::GetInstance()
{
    static NetworkManager instance;
    return instance;
}

std::string NetworkManager::ExecuteCommand(const std::string &command)
{
    return ExecCommandSafe(command.c_str());
}

bool NetworkManager::IsInterfaceExist(const std::string &ifname)
{
    std::string result = ExecuteCommand("ip link show " + ifname);
    return !result.empty();
}

NetIfType NetworkManager::GetInterfaceType(const std::string &ifname)
{
    if (ifname.find("eth") == 0) {
        return NetIfType::ETHERNET;
    } else if (ifname.find("wlan") == 0 || ifname.find("wl") == 0) {
        return NetIfType::WIFI;
    } else if (ifname == "lo") {
        return NetIfType::LOOPBACK;
    } else if (ifname.find("ppp") == 0 || ifname.find("rmnet") == 0) {
        return NetIfType::CELLULAR;
    }

    return NetIfType::UNKNOWN;
}

NetIfInfo NetworkManager::ParseIpAddressOutput(const std::string &output, const std::string &ifname)
{
    NetIfInfo info;
    info.name = ifname;
    info.type = GetInterfaceType(ifname);
    info.status = NetIfStatus::UNKNOWN;
    info.hasIpv4 = false;
    info.gateway = "";

    // 解析MAC地址
    std::regex macRegex("link/ether ([0-9a-f:]+)", std::regex::icase);
    std::smatch macMatch;
    if (std::regex_search(output, macMatch, macRegex)) {
        info.macAddress = macMatch[1];
    }

    // 解析接口状态
    std::regex stateRegex("state (UP|DOWN)", std::regex::icase);
    std::smatch stateMatch;
    if (std::regex_search(output, stateMatch, stateRegex)) {
        std::string state = stateMatch[1];
        if (state == "UP") {
            info.status = NetIfStatus::UP;
        } else if (state == "DOWN") {
            info.status = NetIfStatus::DOWN;
        }
    }

    // 解析IPv4地址
    std::regex ipv4Regex("inet ([0-9.]+)/([0-9]+)", std::regex::icase);
    std::smatch ipv4Match;
    if (std::regex_search(output, ipv4Match, ipv4Regex)) {
        info.ipv4Address = ipv4Match[1];
        int prefix = std::stoi(ipv4Match[2]);
        info.ipv4Mask = CidrToNetmask(prefix);
        info.hasIpv4 = true;
    }

    // 获取默认网关信息
    std::string routeOutput = ExecuteCommand("ip route show dev " + ifname);
    std::regex gatewayRegex("default via ([0-9.]+)", std::regex::icase);
    std::smatch gatewayMatch;
    if (std::regex_search(routeOutput, gatewayMatch, gatewayRegex)) {
        info.gateway = gatewayMatch[1];
    }

    return info;
}

std::vector<NetIfInfo> NetworkManager::GetNetworkInterfaces()
{
    std::vector<NetIfInfo> interfaces;
    std::string output = ExecuteCommand("ip -o link show");
    std::istringstream iss(output);
    std::string line;
    std::regex ifaceRegex("^[0-9]+: ([^:@]+)[@:]", std::regex::icase);

    while (std::getline(iss, line)) {
        std::smatch match;
        if (std::regex_search(line, match, ifaceRegex)) {
            std::string ifname = match[1];
            // 跳过回环接口
            if (GetInterfaceType(ifname) == NetIfType::LOOPBACK) {
                continue;
            }
            std::string ifDetail = ExecuteCommand("ip addr show " + ifname);
            NetIfInfo info = ParseIpAddressOutput(ifDetail, ifname);
            interfaces.push_back(info);
        }
    }

    return interfaces;
}

NetIfInfo NetworkManager::GetNetworkInterface(const std::string &ifname)
{
    if (!IsInterfaceExist(ifname)) {
        return NetIfInfo();
    }

    std::string output = ExecuteCommand("ip addr show " + ifname);
    return ParseIpAddressOutput(output, ifname);
}

bool NetworkManager::SetInterfaceStatus(const std::string &ifname, NetIfStatus status)
{
    if (!IsInterfaceExist(ifname)) {
        return false;
    }

    std::string command;
    if (status == NetIfStatus::UP) {
        command = "ip link set " + ifname + " up";
    } else if (status == NetIfStatus::DOWN) {
        command = "ip link set " + ifname + " down";
    } else {
        return false;
    }

    std::string output = ExecuteCommand(command);

    // 验证状态是否已更改
    NetIfInfo info = GetNetworkInterface(ifname);
    return info.status == status;
}

bool NetworkManager::ConfigureStaticIp(const std::string &ifname,
                                       const std::string &address,
                                       const std::string &netmask,
                                       const std::string &gateway)
{
    if (!IsInterfaceExist(ifname)) {
        return false;
    }

    // 首先清除原有IP地址
    ExecuteCommand("ip addr flush dev " + ifname);

    // 计算CIDR前缀
    int prefix = GetNetmaskPrefix(netmask);

    // 设置IP地址
    std::string ipCmd = "ip addr add " + address + "/" + std::to_string(prefix) + " dev " + ifname;
    ExecuteCommand(ipCmd);

    // 设置默认网关（如果提供）
    if (!gateway.empty()) {
        ExecuteCommand("ip route add default via " + gateway + " dev " + ifname);
    }

    // 确保接口处于启用状态
    SetInterfaceStatus(ifname, NetIfStatus::UP);

    // 验证配置是否成功
    NetIfInfo info = GetNetworkInterface(ifname);
    return (info.ipv4Address == address);
}

bool NetworkManager::ConfigureDhcp(const std::string &ifname)
{
    if (!IsInterfaceExist(ifname)) {
        return false;
    }

    // 首先停止任何可能正在运行的udhcpc进程
    ExecuteCommand("killall -q " + DHCP_COMMAND);

    // 确保接口处于启用状态
    SetInterfaceStatus(ifname, NetIfStatus::UP);

    // 启动DHCP客户端
    // -f: 前台运行
    // -q: 安静模式
    // -i: 指定接口
    // -n: 不配置接口
    std::string command = DHCP_COMMAND + " -f -q -i " + ifname;
    ExecuteCommand(command);

    // 给DHCP客户端一些时间来获取IP地址
    sleep(2);

    // 验证是否获取到IP地址
    NetIfInfo info = GetNetworkInterface(ifname);
    return info.hasIpv4;
}

bool NetworkManager::AddRoute(const std::string &destination,
                              const std::string &gateway,
                              const std::string &netmask,
                              const std::string &ifname,
                              int metric)
{
    if (!IsInterfaceExist(ifname)) {
        return false;
    }

    // 计算CIDR前缀
    int prefix = GetNetmaskPrefix(netmask);

    // 构建路由命令
    std::string command =
        "ip route add " + destination + "/" + std::to_string(prefix) + " via " + gateway + " dev " + ifname;

    // 添加度量值（如果提供）
    if (metric > 0) {
        command += " metric " + std::to_string(metric);
    }

    ExecuteCommand(command);

    // 验证路由是否已添加
    std::string routeTable = ExecuteCommand("ip route show");
    std::string routePattern = destination + "/" + std::to_string(prefix) + " via " + gateway;
    return routeTable.find(routePattern) != std::string::npos;
}

bool NetworkManager::DeleteRoute(const std::string &destination,
                                 const std::string &gateway,
                                 const std::string &netmask,
                                 const std::string &ifname)
{
    if (!IsInterfaceExist(ifname)) {
        return false;
    }

    // 计算CIDR前缀
    int prefix = GetNetmaskPrefix(netmask);

    // 构建路由命令
    std::string command =
        "ip route del " + destination + "/" + std::to_string(prefix) + " via " + gateway + " dev " + ifname;

    ExecuteCommand(command);

    // 验证路由是否已删除
    std::string routeTable = ExecuteCommand("ip route show");
    std::string routePattern = destination + "/" + std::to_string(prefix) + " via " + gateway;
    return routeTable.find(routePattern) == std::string::npos;
}

std::vector<RouteInfo> NetworkManager::GetRouteTable()
{
    std::vector<RouteInfo> routes;
    std::string output = ExecuteCommand("ip route show");
    std::istringstream iss(output);
    std::string line;

    // 简单解析路由表输出
    // 注意：这是一个简化版解析器，实际的ip route输出可能更复杂
    while (getline(iss, line)) {
        RouteInfo route;

        if (line.find("default") == 0) {
            // 默认路由
            route.destination = "0.0.0.0";
            route.netmask = "0.0.0.0";

            std::regex viaRegex("via ([0-9.]+)", std::regex::icase);
            std::smatch viaMatch;
            if (std::regex_search(line, viaMatch, viaRegex)) {
                route.gateway = viaMatch[1];
            }

            std::regex devRegex("dev ([^ ]+)", std::regex::icase);
            std::smatch devMatch;
            if (std::regex_search(line, devMatch, devRegex)) {
                route.ifname = devMatch[1];
            }

            std::regex metricRegex("metric ([0-9]+)", std::regex::icase);
            std::smatch metricMatch;
            if (std::regex_search(line, metricMatch, metricRegex)) {
                route.metric = std::stoi(metricMatch[1]);
            } else {
                route.metric = 0;
            }

            routes.push_back(route);
        } else if (line.find("via") != std::string::npos) {
            // 普通路由
            std::regex destRegex("^([0-9.]+/[0-9]+)", std::regex::icase);
            std::smatch destMatch;
            if (std::regex_search(line, destMatch, destRegex)) {
                std::string cidrDest = destMatch[1];
                size_t slashPos = cidrDest.find('/');
                if (slashPos != std::string::npos) {
                    route.destination = cidrDest.substr(0, slashPos);
                    int prefix = std::stoi(cidrDest.substr(slashPos + 1));
                    route.netmask = CidrToNetmask(prefix);
                }
            }

            std::regex viaRegex("via ([0-9.]+)", std::regex::icase);
            std::smatch viaMatch;
            if (std::regex_search(line, viaMatch, viaRegex)) {
                route.gateway = viaMatch[1];
            }

            std::regex devRegex("dev ([^ ]+)", std::regex::icase);
            std::smatch devMatch;
            if (std::regex_search(line, devMatch, devRegex)) {
                route.ifname = devMatch[1];
            }

            std::regex metricRegex("metric ([0-9]+)", std::regex::icase);
            std::smatch metricMatch;
            if (std::regex_search(line, metricMatch, metricRegex)) {
                route.metric = std::stoi(metricMatch[1]);
            } else {
                route.metric = 0;
            }

            routes.push_back(route);
        }
    }

    return routes;
}

bool NetworkManager::SetDnsServers(const std::vector<std::string> &servers)
{
    if (servers.empty()) {
        return false;
    }

    // 打开resolv.conf文件
    std::ofstream resolvFile(DNS_CONFIG_FILE);
    if (!resolvFile.is_open()) {
        return false;
    }

    // 写入DNS服务器
    resolvFile << "# Generated by NetworkManager\n";
    for (const auto &server : servers) {
        resolvFile << "nameserver " << server << "\n";
    }

    resolvFile.close();
    return true;
}

std::vector<std::string> NetworkManager::GetDnsServers()
{
    std::vector<std::string> servers;
    std::ifstream resolvFile(DNS_CONFIG_FILE);

    if (!resolvFile.is_open()) {
        return servers;
    }

    std::string line;
    std::regex dnsRegex("^nameserver\\s+([0-9.]+)\\s*$", std::regex::icase);

    while (getline(resolvFile, line)) {
        std::smatch match;
        if (std::regex_search(line, match, dnsRegex)) {
            servers.push_back(match[1]);
        }
    }

    resolvFile.close();
    return servers;
}

} // namespace Hal
} // namespace El
